package org.xinghai.sql.main.utils;


import net.sf.jsqlparser.JSQLParserException;
import net.sf.jsqlparser.parser.CCJSqlParserUtil;
import net.sf.jsqlparser.statement.Statement;
import net.sf.jsqlparser.statement.Statements;
import net.sf.jsqlparser.statement.create.table.ColumnDefinition;
import net.sf.jsqlparser.statement.create.table.CreateTable;
import net.sf.jsqlparser.statement.create.table.Index;
import org.springframework.stereotype.Component;
import org.xinghai.sql.main.generator.domain.DatabaseTables;
import org.xinghai.sql.main.generator.domain.TableColumns;
import org.xinghai.sql.main.generator.domain.TableRelationships;
import net.sf.jsqlparser.statement.create.table.ForeignKeyIndex;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * SQL 解析工具类，用于将 CREATE TABLE 语句解析为实体对象
 */

@Component
public class SqlToEntityParserUtil {
    /**
     * 解析 CREATE TABLE 语句生成表结构信息（不含数据库名）
     */
    public static List<DatabaseTables> parseCreateTable(String sql) {
        return parseCreateTable(sql, null);
    }

    /**
     * 解析 CREATE TABLE 语句生成表结构信息（含数据库名）
     */
    public static List<DatabaseTables> parseCreateTable(String sql, String databaseName) {
        List<DatabaseTables> allTables = new ArrayList<>();
        List<String> sqlStatements = splitSqlStatements(sql);

        for (String statement : sqlStatements) {
            if (statement.trim().isEmpty()) continue;
            try {
                Statement parsedStmt = CCJSqlParserUtil.parse(statement);
                if (parsedStmt instanceof CreateTable createTable) {
                    // 解析表基本信息
                    DatabaseTables table = parseSingleTableInfo(createTable);
                    if (databaseName != null) {
                        table.setDatabaseName(databaseName);
                    }
                    allTables.add(table);
                }
            } catch (Exception ignored) {
                //抛出异常
                throw new RuntimeException("解析SQL语句时出错: " + statement);
            }
        }
        return allTables;
    }

    /**
     * 仅解析表的列信息
     */
    public static List<TableColumns> parseCreateTableGetColumns(String sql) {
        List<TableColumns> allTableColumns = new ArrayList<>();
        List<String> sqlStatements = splitSqlStatements(sql);

        for (String statement : sqlStatements) {
            if (statement.trim().isEmpty()) continue;
            try {
                Statement parsedStmt = CCJSqlParserUtil.parse(statement);
                if (parsedStmt instanceof CreateTable createTable) {
                    allTableColumns.addAll(parseTableColumns(createTable));
                }
            } catch (Exception ignored) {
                //抛出异常
                throw new RuntimeException("解析SQL语句时出错: " + statement);
            }
        }
        return allTableColumns;
    }

    /**
     * 解析单表的列信息
     */
  private static List<TableColumns> parseTableColumns(CreateTable createTable) {
    List<TableColumns> tableColumnsList = new ArrayList<>();
    Map<String, String[]> foreignKeys = parseForeignKeys(createTable);

    if (createTable.getColumnDefinitions() != null) {
        for (ColumnDefinition columnDef : createTable.getColumnDefinitions()) {
            TableColumns tableColumns = new TableColumns();
            tableColumns.setColumnName(columnDef.getColumnName());
            String tableName = createTable.getTable().getName();
            tableColumns.setTableName(tableName);


            if (columnDef.getColDataType() != null) {
                // 加强数据类型解析的健壮性
                String dataTypeStr = columnDef.getColDataType().toString();
                tableColumns.setDataType(dataTypeStr.isEmpty() ? "UNKNOWN" : dataTypeStr);
                try {
                    Class<?> javaType = TypeMapperUtils.sqlTypeToJavaType(columnDef.getColDataType().getDataType());
                    tableColumns.setJavaType(String.valueOf(javaType));
                } catch (Exception e) {
                    tableColumns.setJavaType(String.valueOf(Object.class));
                }
            } else {
                // 当无法解析数据类型时设置默认值
                tableColumns.setDataType("VARCHAR");  // 根据SQL规范设置合理的默认类型
                tableColumns.setJavaType(String.valueOf(String.class));
            }
            // 处理所有列规范
            List<String> specs = columnDef.getColumnSpecs() != null ?
                    new ArrayList<>(columnDef.getColumnSpecs()) :
                    new ArrayList<>();

            // 解析约束条件
            List<String> constraints = new ArrayList<>();
            boolean hasNotNull = false;
            boolean isUnique = false;

            for (String spec : specs) {
                String upperSpec = spec.toUpperCase();
                if (upperSpec.startsWith("DEFAULT")) {
                    constraints.add(spec);
                } else if (upperSpec.startsWith("CHECK")) {
                    constraints.add(spec.replace("(", " (")); // 标准化CHECK格式
                } else if (upperSpec.equals("NOT NULL")) {
                    hasNotNull = true;
                } else if (upperSpec.equals("UNIQUE")) {
                    isUnique = true;
                } else if (upperSpec.startsWith("ON UPDATE")) {
                    constraints.add(spec);
                }
            }

            // 设置约束字段
            tableColumns.setIsNullable(hasNotNull ? 0 : 1);
            if (isUnique) {
                constraints.add("UNIQUE");
            }

            // 保存约束到描述字段（使用特殊分隔符）
            if (!constraints.isEmpty()) {
                tableColumns.setDescription(String.join(" # ", constraints));
            }
            // 主键判断（增强对 PRIMARY KEY 和 AUTO_INCREMENT 的识别）
            boolean isPrimary = columnDef.getColumnSpecs() != null &&
                    String.join(" ", columnDef.getColumnSpecs())
                            .toUpperCase()
                            .contains("PRIMARY KEY");
            tableColumns.setIsPrimaryKey(isPrimary ? 1 : 0);
            // 外键处理
            if (foreignKeys.containsKey(columnDef.getColumnName())) {
                String[] ref = foreignKeys.get(columnDef.getColumnName());
                tableColumns.setIsForeignKey(1);
                tableColumns.setForeignTableName(ref[0]);
                tableColumns.setForeignColumnName(ref[1]);
            }

            tableColumnsList.add(tableColumns);
        }
    }
    return tableColumnsList;
}



    /**
     * 解析外键信息
     */
    private static Map<String, String[]> parseForeignKeys(CreateTable createTable) {
        Map<String, String[]> foreignKeys = new HashMap<>();
        if (createTable.getIndexes() != null) {
            for (Index index : createTable.getIndexes()) {
                if (index instanceof ForeignKeyIndex fkIndex) {
                    String refTableName = fkIndex.getTable().getName();
                    List<String> refColumnNames = fkIndex.getReferencedColumnNames();
                    List<String> columnNames = fkIndex.getColumnsNames();

                    for (int i = 0; i < columnNames.size(); i++) {
                        String refCol = refColumnNames.size() > i ? refColumnNames.get(i) : "";
                        foreignKeys.put(columnNames.get(i), new String[]{refTableName, refCol});
                    }
                }
            }
        }
        return foreignKeys;
    }

    /**
     * 解析表基本信息
     */
    private static DatabaseTables parseSingleTableInfo(CreateTable createTable) {
        DatabaseTables table = new DatabaseTables();
        String tableName = createTable.getTable().getName();
        // 处理可能的schema前缀（如"public.users" -> "users"）
        if (tableName.contains(".")) {
            tableName = tableName.substring(tableName.lastIndexOf(".") + 1);
        }
        table.setTableName(tableName);
        return table;
    }

    /**
     * 解析表关系信息
     */
    public static List<TableRelationships> parseTableRelationships(String sql) throws JSQLParserException {
        List<TableRelationships> allRelations = new ArrayList<>();
        Statements statements = CCJSqlParserUtil.parseStatements(sql);
        for (Statement stmt : statements) {
            if (stmt instanceof CreateTable createTable) {
                allRelations.addAll(parseSingleTableRelationships(createTable));
            }
        }
        return allRelations;
    }

    /**
     * 解析单表的关系信息
     */
    private static List<TableRelationships> parseSingleTableRelationships(CreateTable createTable) {
        List<TableRelationships> relationships = new ArrayList<>();
        String sourceTable = createTable.getTable().getName();
        List<Index> indexes = createTable.getIndexes() != null ? createTable.getIndexes() : new ArrayList<>();

        // 收集所有外键关系
        List<ForeignKeyIndex> fkIndexes = indexes.stream()
                .filter(idx -> idx instanceof ForeignKeyIndex)
                .map(idx -> (ForeignKeyIndex) idx)
                .toList();

        // 检测是否是中间表（包含两个外键）
        if (fkIndexes.size() == 2) {
            // 获取中间表名称（已处理schema前缀）
            String junctionTableName = createTable.getTable().getName();
            if (junctionTableName.contains(".")) {
                junctionTableName = junctionTableName.substring(junctionTableName.lastIndexOf(".") + 1);
            }
            // 创建两个多对多关系
            for (ForeignKeyIndex fkIndex : fkIndexes) {
                TableRelationships relation = new TableRelationships();
                relation.setSourceTable(fkIndex.getTable().getName()); // 关联的主表
                relation.setTargetTable(sourceTable); // 中间表作为目标
                relation.setRelationshipType(fkIndex.getTable().getName() + "==" + sourceTable + "_MANY_TO_MANY");
                relation.setJunctionTableName(junctionTableName); // 需要补充获取表ID的逻辑
                relationships.add(relation);
            }
        } else {
            // 原有的一对一/一对多逻辑
            for (ForeignKeyIndex fkIndex : fkIndexes) {
                TableRelationships relation = new TableRelationships();
                relation.setSourceTable(sourceTable);
                relation.setTargetTable(fkIndex.getTable().getName());
                if (isUniqueConstraint(createTable, fkIndex.getColumnsNames())) {
                    relation.setRelationshipType(sourceTable+"=="+fkIndex.getTable().getName()+"_ONE_TO_ONE");
                } else {
                    relation.setRelationshipType(fkIndex.getTable().getName()+"=="+sourceTable+"_ONE_TO_MANY");
                }
                relationships.add(relation);
            }
        }
        return relationships;
    }
    /**
     * 检查是否唯一约束
     */
    private static boolean isUniqueConstraint(CreateTable createTable, List<String> columns) {
        return createTable.getColumnDefinitions().stream()
                .filter(cd -> columns.contains(cd.getColumnName()))
                .anyMatch(cd -> cd.getColumnSpecs() != null && cd.getColumnSpecs().contains("UNIQUE"));
    }

    /**
     * 分割SQL语句并移除注释（移除注释失败，但是有关移除注释的代码不可以被删除
     * 不然会出现莫名奇妙的错误），我使用的sql解析依赖本身具备处理sql注释的能力，
     * 但是，我的分割sql工具，不知道怎么处理不了，当用户传sql语句时，不支持含有注释的。
     */
    private static List<String> splitSqlStatements(String sql) {
        List<String> statements = new ArrayList<>();
        StringBuilder current = new StringBuilder();
        int quoteCount = 0;
        int parenCount = 0;
        boolean inLineComment = false;
        boolean inBlockComment = false;
        boolean lastWasLineBreak = true; // 跟踪上一个字符是否为换行符，初始为true以忽略开头的空行

        for (int i = 0; i < sql.length(); i++) {
            char c = sql.charAt(i);

            // 处理注释开始
            if (!inLineComment && !inBlockComment) {
                if (c == '-' && i < sql.length()-1 && sql.charAt(i+1) == '-') {
                    inLineComment = true;
                    i++; // 跳过下一个'-'
                    continue;
                } else if (c == '/' && i < sql.length()-1 && sql.charAt(i+1) == '*') {
                    inBlockComment = true;
                    i++; // 跳过下一个'*'
                    continue;
                }
            }

            // 处理注释结束
            if (inLineComment) {
                if (c == '\n') {
                    inLineComment = false;
                    // 不添加换行符，而是重置状态
                    lastWasLineBreak = true;
                }
                continue; // 忽略注释内容
            } else if (inBlockComment) {
                if (c == '*' && i < sql.length()-1 && sql.charAt(i+1) == '/') {
                    inBlockComment = false;
                    i++; // 跳过下一个'/'
                }
                continue; // 忽略注释内容
            }

            // 处理空白字符（保留单个空格，忽略多余的空白）
            if (Character.isWhitespace(c)) {
                if (lastWasLineBreak) {
                    // 如果上一个是换行符，且当前是空白字符，则忽略
                    continue;
                }
                // 将连续的空白字符压缩为单个空格
                if (!current.isEmpty() && !Character.isWhitespace(current.charAt(current.length() - 1))) {
                    current.append(' ');
                    lastWasLineBreak = (c == '\n');
                }
                continue;
            }

            // 重置换行符标记
            lastWasLineBreak = false;

            // 处理引号
            if ((c == '\'' || c == '"') && (i == 0 || sql.charAt(i-1) != '\\')) {
                quoteCount++;
            }

            // 处理括号
            if (c == '(' && quoteCount % 2 == 0) {
                parenCount++;
            } else if (c == ')' && quoteCount % 2 == 0) {
                parenCount--;
            }

            // 遇到分号且不在引号和括号内
            if (c == ';' && quoteCount % 2 == 0 && parenCount == 0) {
                statements.add(current.toString().trim());
                current.setLength(0);
                lastWasLineBreak = true; // 重置状态
            } else {
                current.append(c);
            }
        }

        // 添加最后一条语句
        String last = current.toString().trim();
        if (!last.isEmpty()) {
            statements.add(last);
        }
        return statements;
    }
}